From ab60cbd86a852121a7181275a45545070d06f6a6 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 17 Nov 2016 03:31:15 +0100 Subject: [PATCH] snapshot: Implement gtk_snapshot_clips_rect() And use this to cull widgets and gadgets that are completely outside the clip region. A potential optimization is to apply this clip region to cairo contexts created with gtk_snapshot_append_cairo_node(), but for that we'd need to apply the inverse matrix to the clip region, and that causes rounding errors. Plus, I hope that cairo drawing becomes exceedingly rare so it won't be used for the whole widget factory like today (which might also explain why no culling happens in the widget factory outside the header bar. --- gtk/gtksnapshot.c | 77 +++++++++++++++++++++++++--------------- gtk/gtksnapshotprivate.h | 2 ++ gtk/gtkwidget.c | 2 ++ 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index a86df11d89..5733d85176 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -55,6 +55,26 @@ gtk_snapshot_state_set_transform (GtkSnapshotState *state, const graphene_matrix_t *transform) { graphene_matrix_init_from_matrix (&state->transform, transform); + + state->world_is_valid = FALSE; +} + +static const graphene_matrix_t * +gtk_snapshot_state_get_world_transform (GtkSnapshotState *state) +{ + if (!state->world_is_valid) + { + if (state->parent) + graphene_matrix_multiply (gtk_snapshot_state_get_world_transform (state->parent), + &state->transform, + &state->world_transform); + else + graphene_matrix_init_from_matrix (&state->world_transform, &state->transform); + + state->world_is_valid = TRUE; + } + + return &state->world_transform; } void @@ -140,34 +160,6 @@ gtk_snapshot_get_renderer (const GtkSnapshot *state) return state->renderer; } -#if 0 -GskRenderNode * -gtk_snapshot_create_render_node (const GtkSnapshot *state, - const char *name, - ...) -{ - GskRenderNode *node; - - node = gsk_renderer_create_render_node (state->renderer); - - if (name) - { - va_list args; - char *str; - - va_start (args, name); - str = g_strdup_vprintf (name, args); - va_end (args); - - gsk_render_node_set_name (node, str); - - g_free (str); - } - - return node; -} -#endif - void gtk_snapshot_set_transform (GtkSnapshot *snapshot, const graphene_matrix_t *transform) @@ -325,11 +317,38 @@ gtk_snapshot_push_cairo_node (GtkSnapshot *state, return gsk_render_node_get_draw_context (node, state->renderer); } +static void +rectangle_init_from_graphene (cairo_rectangle_int_t *cairo, + const graphene_rect_t *graphene) +{ + cairo->x = floorf (graphene->origin.x); + cairo->y = floorf (graphene->origin.y); + cairo->width = ceilf (graphene->origin.x + graphene->size.width) - cairo->x; + cairo->height = ceilf (graphene->origin.y + graphene->size.height) - cairo->y; +} + gboolean gtk_snapshot_clips_rect (GtkSnapshot *snapshot, const graphene_rect_t *bounds) { - return FALSE; + cairo_rectangle_int_t rect; + + if (snapshot->state) + { + const graphene_matrix_t *world; + graphene_rect_t transformed; + + world = gtk_snapshot_state_get_world_transform (snapshot->state); + + graphene_matrix_transform_bounds (world, bounds, &transformed); + rectangle_init_from_graphene (&rect, &transformed); + } + else + { + rectangle_init_from_graphene (&rect, bounds); + } + + return cairo_region_contains_rectangle (snapshot->clip_region, &rect) == CAIRO_REGION_OVERLAP_OUT; } void diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h index c9899d004f..ff9d1b62c0 100644 --- a/gtk/gtksnapshotprivate.h +++ b/gtk/gtksnapshotprivate.h @@ -30,6 +30,8 @@ struct _GtkSnapshotState { GskRenderNode *node; graphene_matrix_t transform; + graphene_matrix_t world_transform; + guint world_is_valid : 1; }; struct _GtkSnapshot { diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 7e4c56d56e..4045e3f501 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -15657,6 +15657,8 @@ gtk_widget_snapshot (GtkWidget *widget, gtk_widget_get_clip (widget, &clip); _gtk_widget_get_allocation (widget, &alloc); graphene_rect_init (&bounds, alloc.x - clip.x, alloc.y - clip.y, clip.width, clip.height); + if (gtk_snapshot_clips_rect (snapshot, &bounds)) + return; /* Compatibility mode: if the widget does not have a render node, we draw * using gtk_widget_draw() on a temporary node -- 2.30.2